package com.lg.concurrent.lock;

import lombok.SneakyThrows;

import java.util.concurrent.TimeUnit;

/**
 * 一个东西被 同一个线程锁住，那么这个线程可以重复进入这个锁
 */
public class LockSomeThing {
    public Object o1 = new Object();
    public Object o2 = new Object();

    //方法和子方法 锁的都是同一个对象，所以可以重入
    @SneakyThrows
    public synchronized void doing() {

        System.out.println(Thread.currentThread().getName() + " doing start");
        TimeUnit.SECONDS.sleep(3);
        add();
        System.out.println(Thread.currentThread().getName() + " doing end");
    }

    @SneakyThrows
    public synchronized void add() {
        System.out.println(Thread.currentThread().getName() + " add start");
        TimeUnit.SECONDS.sleep(3);
        System.out.println(Thread.currentThread().getName() + " add end");
    }

    //两个锁 锁的不是同一个对象 无法重入
    @SneakyThrows
    public void reLock1() {
        System.out.println(Thread.currentThread().getName() + "into reLock1");
        synchronized (o1) {
            System.out.println(Thread.currentThread().getName() + "into o1 to doing");
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName() + "into o1 doing over to o2");
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName() + "into o2");
            }
        }
        System.out.println(Thread.currentThread().getName() + "end reLock1");
    }

    @SneakyThrows
    public void reLock2() {
        System.out.println(Thread.currentThread().getName() + "into reLock2");
        synchronized (o2) {
            System.out.println(Thread.currentThread().getName() + "into o2 to doing");
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName() + "into o2 doing over to o1");
            synchronized (o1) {
                System.out.println(Thread.currentThread().getName() + "into o1");
            }
        }
        System.out.println(Thread.currentThread().getName() + "end reLock2");
    }

    public static void main(String[] args) {
        LockSomeThing reentrantLockTest = new LockSomeThing();

//        reentrantLockTest.doing();
//        new Thread(()->{
//            reentrantLockTest.add();
//        }).start();

        new Thread(() -> {
            reentrantLockTest.reLock1();
        }).start();

        new Thread(() -> {
            reentrantLockTest.reLock2();
        }).start();
    }
}
